#pragma once
#include <cassert>
#include <iostream>
#include <cstring>
using std::cout;
using std::cin;
using std::endl;

namespace real
{
    template<class T>
    class vector
    {
        private:
            T* _start = nullptr;
            T* _finish = nullptr;
            T* _end_of_storage = nullptr;

        public:
            typedef T* iterator ;
            typedef const T* const_iterator ;

            iterator begin()
            {
                return _start;
            }
            iterator end()
            {
                return _finish;
            }
            const_iterator begin() const
            {
                return _start;
            }
            const_iterator end() const
            {
                return _finish;
            }

            size_t size() const
            {
                return size_t(_finish - _start);
            }

            size_t capacity() const
            {
                return size_t(_end_of_storage - _start);
            }

            bool empty() const
            {
                return _start == _finish;
            }

            void push_back(const T& v)
            {
                if(_end_of_storage==_finish)
                {
                    reserve(capacity()==0?4:capacity()*2);
                }
                *_finish = v ;
                _finish++;
            }

            iterator erase(iterator pos)
            {
                assert(!empty());
                assert(pos<_finish);
                size_t len = size_t(pos-_start);
                while(pos!=_finish)
                {
                    *pos = *(pos+1);
                    pos++;
                }
                --_finish;
                return _start+len;
            }

            iterator erase(iterator first, iterator last)
            {
                assert(!empty());
                assert(last<=_finish);
                size_t len = size_t(last-_start);
                size_t elem_len = size_t(last-first);

                while(first!=last)
                {
                    *first = *(first+elem_len);
                    first++;
                }
                _finish -= elem_len;
                return _start+len;
            }

            void reserve(size_t n)
            {
                if( n > capacity())
                {   
                    cout << "Reserve called " << n << endl;
                    T* tmp = new T[n];
                    for (size_t i = 0; i < size(); i++ ) {
                        tmp[i] = _start[i];
                    }                    
                    _end_of_storage = tmp+n;
                    _finish = tmp+size();
                    delete [] _start;
                    _start = tmp ;
                }
            }

            // deafault struct
            // vector()
            // {}
            vector() = default;

            vector(const vector<T>& v)
            {
                // T* tmp = new T[v.size()] ;
                // // memcpy(tmp, v._start, v.size()); 编译直接不通过
                // for (size_t i = 0; i < v.size(); i++)
                // {
                //     tmp[i] = v._start[i];
                // }
                // _start = tmp;
                // _finish = _end_of_storage = _start+v.size();

                reserve(v.size());
                for(auto& i: v)
                {
                    push_back(i);
                }
            }

            vector(const T& v)
            {
                push_back(v);
            }

            ~vector()
            {
                delete [] _start;
                _start = _finish = _end_of_storage = nullptr;
            }

            void clear()
            {
                _finish = _start;
            }

            void swap(vector<T>& v)
            {
                std::swap(_start, v._start);
                std::swap(_finish, v._finish);
                std::swap(_end_of_storage, v._end_of_storage);
            }

            // 现代写法
            vector<T>& operator=(vector<T> v)
            {
                swap(v);
                return *this;
            }
            // vector<T>& operator=(const vector<T>& v)
            // {
            //     if(this != &v)
            //     {
            //         clear();
            //         reserve(v.size());
            //         for(auto& i: v)
            //         {
            //             push_back(i);
            //         }

            //     }
            //     return *this;
            // }

            T& operator[](size_t i)
            {
                assert(i<size());
                return _start[i];
            }



    };

    template<class container>
    void print_container(container start, container end)
    {
        while(start != end)
        {
            cout << *start++ << " ";
        }
        cout << endl;
    }
}